#include "24C02.hpp"

void EEPROM_24C02::run(void *parameter)
{
    //* 1. initialization
    if (!this->init(0x00))
        rt_kprintf("AA24C02 init failed.\r\n");
    if (!this->check())
        rt_kprintf("AA24C02 check invalid.\r\n");

    rt_uint8_t i;
    rt_uint8_t ret;
    while (1)
    {

        this->writeByte(0x00, i);
        i++;

        rt_thread_mdelay(100);
        this->readByte(0x00, ret);
        rt_kprintf("read data: %d\r\n", ret);

        rt_thread_mdelay(100);
    }
}

bool EEPROM_24C02::init(const rt_uint8_t &addr = 0X00)
{
    // check address valid
    if (addr > 0x07)
        return false;

    if (this->i2cInit("i2c1"))
    {
        this->address = addr;
        return true;
    }
    return false;
}

bool EEPROM_24C02::check()
{
    const rt_uint16_t readAddr = EEPROM_24C02::MAX_MEM_ADDRESS - 1;
    rt_uint8_t ret;

    // prevent the eeprom from being written
    this->readByte(readAddr, ret);

    if (ret == 0X55)
        return true;
    else // Exclude the first init
    {
        this->writeByte(readAddr, 0x55);
        rt_thread_mdelay(5);
        this->readByte(readAddr, ret);
        if (ret == 0X55)
            return true;
    }
    return false;
}

bool EEPROM_24C02::readByte(const rt_uint8_t &readAddr, rt_uint8_t &data)
{
    //* 1. send read address to eeprom
    const rt_uint16_t addr = EEPROM_24C02::UNIV_ADDR | this->address;
    if (!this->sendByte(addr, readAddr))
        return false;

    //* 2. read data from eeprom
    return this->recvByte(addr, data);
}

bool EEPROM_24C02::writeByte(const rt_uint8_t &writeAddr, const rt_uint8_t &data)
{
    //* 1. prepare data to send
    const rt_uint16_t addr = EEPROM_24C02::UNIV_ADDR | this->address;
    vector<rt_uint8_t> vec;
    vec.push_back(writeAddr);
    vec.push_back(data);

    //* 2. send data to eeprom
    return this->send(addr, vec);
}

bool EEPROM_24C02::read(const rt_uint8_t &readAddr, vector<rt_uint8_t> &data, const rt_uint32_t &numToRead)
{
    // Exceeded address limit
    if (readAddr + numToRead > EEPROM_24C02::MAX_MEM_ADDRESS)
        return false;

    //* 1. prepare vector to store data
    data.clear();
    data.reserve(numToRead);

    //* 2. read data byte by byte
    for (rt_uint32_t i = 0; i < numToRead; i++)
    {
        rt_uint8_t dataByte;
        if (!this->readByte(readAddr + i, dataByte))
            return false;
        data.push_back(dataByte);
    }
    return true;
}

bool EEPROM_24C02::read(const rt_uint8_t &readAddr, string &str, const rt_uint32_t &numToRead)
{
    vector<rt_uint8_t> data;
    data.reserve(numToRead);
    if (!this->read(readAddr, data, numToRead))
        return false;

    str.assign(data.begin(), data.end());
    return true;
}

bool EEPROM_24C02::write(rt_uint8_t writeAddr, const vector<rt_uint8_t> &data)
{
    // Exceeded address limit
    if (writeAddr + data.size() > EEPROM_24C02::MAX_MEM_ADDRESS)
        return false;

    for (const auto &byte : data)
    {
        if (!this->writeByte(writeAddr, byte))
            return false;
        rt_thread_mdelay(2);
        writeAddr++;
    }
    return true;
}

bool EEPROM_24C02::write(rt_uint8_t writeAddr, const string &str)
{
    return this->write(writeAddr, vector<rt_uint8_t>(str.begin(), str.end()));
}
